﻿using System;

namespace PropertyExpression.ControllableQuery
{
    public class Lazy<T>
    {
        private readonly Func<T> func;

        public Lazy(Func<T> func)
        {
            this.func = func;
        }

        private bool valueIsSet;
        private T value;
        public T Value
        {
            get
            {
                if (valueIsSet == false)
                {
                    value = func();
                    valueIsSet = true;
                }
                return value;
            }
        }

        public static implicit operator T(Lazy<T> value)
        {
            return value.Value;
        }
    }

    public class Lazy<T1, TResult>
    {
        private readonly Func<T1, TResult> func;
        private readonly Func<T1, T1, bool> equalFunc;

        public Lazy(Func<T1, TResult> func, Func<T1, T1, bool> equalFunc)
        {
            this.func = func;
            this.equalFunc = equalFunc;
        }

        private TResult cachedValue;
        private T1 cachedArg;
        public TResult GetValue(T1 arg)
        {
            if (valueIsSet == false || !equalFunc(arg, cachedArg))
            {
                cachedValue = func(arg);
                cachedArg = arg;
                valueIsSet = true;
            }
            return cachedValue;
        }

        private bool valueIsSet;
    }

    public static class Lazy
    {
        public static Lazy<TResult> New<TResult>(Func<TResult> func)
        {
            return new Lazy<TResult>(func);
        }


        public static Lazy<T1, TResult> New<T1, TResult>(Func<T1, TResult> func, Func<T1, T1, bool> equalFunc)
        {
            return new Lazy<T1, TResult>(func, equalFunc);
        }
    }
}
